package org.mclll.xwangplugin.dengmi;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.Data;
import lombok.NoArgsConstructor;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.TextColor;
import net.kyori.adventure.text.format.TextDecoration;
import org.bukkit.Bukkit;
import org.bukkit.NamespacedKey;
import org.bukkit.boss.BarColor;
import org.bukkit.boss.BarStyle;
import org.bukkit.boss.KeyedBossBar;
import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.event.player.AsyncPlayerChatEvent;
import org.bukkit.scheduler.BukkitTask;
import org.jetbrains.annotations.NotNull;
import org.mclll.xwangplugin.MclllCustom;
import org.mclll.xwangplugin.dengmi.domain.Question;
import org.mclll.xwangplugin.dengmi.domain.QuestionType;

import java.io.*;
import java.nio.file.Files;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;

public class GameQuestion {
    public static String FILE_NAME = "dengMi.yml";
    private static List<Question> QUESTION_POOL;
    private static Question nowQuestion;
    private static Integer startQuestionTime;
    private static Integer endQuestionTime;
    private static MclllCustom plugin;
    private static Map<String, Integer> nowQuestionRightPlayer;
    public static Map<String, Integer> dengMiTop;
    public static Map<String, Integer> playerSelectCoolDown = Maps.newHashMap();

    /**
     * 每题持续时间 - 秒
     */
    private static Integer timeInterval = 20;
    /**
     * 每题时间间隔 - 秒
     */
    private static Integer duration = 6;
    /**
     * 选择题冷却 - 秒
     */
    private static Integer selectCoolDown = 10;
    /**
     * 运行了多少秒
     */
    private static Integer runSeconds = -1;
    private static final String newDengMi = "tellraw @a [\"\",{\"text\":\"【\",\"bold\":true,\"color\":\"#B6B6DF\"},{\"text\":\"新春灯谜\",\"bold\":true,\"color\":\"red\"},{\"text\":\"】\",\"bold\":true,\"color\":\"#B6B6DF\"},{\"text\":\"野生的灯谜出现了！\",\"bold\":true,\"color\":\"yellow\"}]";
    private static final String answerOutput = "tellraw @a [\"\",{\"text\":\"【\",\"bold\":true,\"color\":\"#B6B6DF\"},{\"text\":\"新春灯谜\",\"bold\":true,\"color\":\"red\"},{\"text\":\"】\",\"bold\":true,\"color\":\"#B6B6DF\"},{\"text\":\"谜底是：\",\"bold\":true,\"color\":\"#00FFC7\"},{\"text\":\"%s\",\"bold\":true,\"color\":\"yellow\"}]";
    private static final String timeOverWaring = "tellraw @a [\"\",{\"text\":\"【\",\"bold\":true,\"color\":\"#B6B6DF\"},{\"text\":\"新春灯谜\",\"bold\":true,\"color\":\"red\"},{\"text\":\"】\",\"bold\":true,\"color\":\"#B6B6DF\"},{\"text\":\"答题时间不多了！加油！\",\"bold\":true,\"color\":\"yellow\"}]";
    private static final String messageOutput = "tellraw @a [\"\",{\"text\":\"【\",\"bold\":true,\"color\":\"#B6B6DF\"},{\"text\":\"新春灯谜\",\"bold\":true,\"color\":\"red\"},{\"text\":\"】\",\"bold\":true,\"color\":\"#B6B6DF\"},{\"text\":\"偷偷告诉你%s\",\"bold\":true,\"color\":\"gray\"}]";
    private static final String dengmiComingSoon = "tellraw @a [\"\",{\"text\":\"【\",\"bold\":true,\"color\":\"#B6B6DF\"},{\"text\":\"新春灯谜\",\"bold\":true,\"color\":\"red\"},{\"text\":\"】\",\"bold\":true,\"color\":\"#B6B6DF\"},{\"text\":\"灯谜将在\",\"bold\":true,\"color\":\"yellow\"},{\"text\":\"5\",\"bold\":true,\"color\":\"#FF0003\"},{\"text\":\"秒钟后\",\"bold\":true,\"color\":\"yellow\"},{\"text\":\"到达\",\"bold\":true,\"color\":\"#FF0000\"},{\"text\":\"，请做好准备！\",\"bold\":true,\"color\":\"yellow\"}]";
    private static final String dengmiEndWaring = "tellraw @a [\"\",{\"text\":\"【\",\"bold\":true,\"color\":\"#B6B6DF\"},{\"text\":\"新春灯谜\",\"bold\":true,\"color\":\"red\"},{\"text\":\"】\",\"bold\":true,\"color\":\"#B6B6DF\"},{\"text\":\"答题时间还有\",\"bold\":true,\"color\":\"yellow\"},{\"text\":\"10\",\"bold\":true,\"color\":\"#FF0003\"},{\"text\":\"秒喽！\",\"bold\":true,\"color\":\"yellow\"},{\"text\":\"加油！\",\"bold\":true,\"color\":\"yellow\"}]";
    private static final String dengmiComingSoonD = "tellraw @a [\"\",{\"text\":\"【\",\"bold\":true,\"color\":\"#B6B6DF\"},{\"text\":\"新春灯谜\",\"bold\":true,\"color\":\"red\"},{\"text\":\"】\",\"bold\":true,\"color\":\"#B6B6DF\"},{\"text\":\"%d\",\"bold\":true,\"color\":\"#FF0003\"}]";
    private static final String acknowledgments = "tellraw @a [\"\",{\"text\":\"【\",\"bold\":true,\"color\":\"#B6B6DF\"},{\"text\":\"新春灯谜\",\"bold\":true,\"color\":\"red\"},{\"text\":\"】\",\"bold\":true,\"color\":\"#B6B6DF\"},{\"text\":\"灯谜都出完啦！！感谢丁丁搜集灯谜！祝大家新年快乐 ~\",\"bold\":true,\"color\":\"yellow\"}]";
    private static final String giveHongBaoCommand = "crate give %s hongbao 1";
    public static void reload(CommandSender sender, MclllCustom mclllCustom) {
        plugin = mclllCustom;
        File dataFolder = plugin.getDataFolder();
        YamlConfiguration configFile = YamlConfiguration.loadConfiguration(new File(dataFolder, FILE_NAME));
        List<?> question = configFile.getList("question", Lists.newArrayList());
        if (question.isEmpty()) {
            sender.sendMessage("没有读取到题目");
            return;
        }
        // 清空题库
        QUESTION_POOL = Lists.newArrayList();
        // 填充题库
        for (Object o : question) {
            Map item = null;
            if (o instanceof Map) {
                item = (Map) o;
            } else {
                continue;
            }
            Question q = new Question();
            q.setQuestion((String) item.get("question"));
            q.setAnswer((String) item.get("answer"));
            q.setMessage((String) item.get("message"));
            if (item.containsKey("type")) {
                try {
                    QuestionType type = QuestionType.valueOf((String) item.get("type"));
                    q.setType(type);
                } catch (Exception ignore) {
                }
            }
            QUESTION_POOL.add(q);
        }
        if (configFile.contains("config")) {
            ConfigurationSection config = configFile.getConfigurationSection("config");
            timeInterval = config.getInt("timeInterval", 20);
            duration = config.getInt("duration", 6);
            selectCoolDown = config.getInt("selectCoolDown", 10);
        }
        sender.sendMessage(String.format("已加载%d道题目, 题目持续时间：%d秒, 题目间隔：%d秒, 选择题冷却时间：%d秒", question.size(), timeInterval, duration, selectCoolDown));
    }

    public static @NotNull BukkitTask start(boolean isGoOn) {
        // 创建好bossBar
        for (int i = 0; i < 3; i++) {
            KeyedBossBar bar = Bukkit.getServer().getBossBar(new NamespacedKey("mclll", "xw" + i));
            if (bar == null) {
                bar = Bukkit.getServer()
                        .createBossBar(new NamespacedKey("mclll", "xw" + i), "", BarColor.YELLOW, BarStyle.SOLID);
            }
            if (!bar.isVisible()) {
                bar.setVisible(false);
            }
        }
        questionAddAll();
        endQuestionTime = 0;
        runSeconds = duration - 6;
        if (!isGoOn) {
            dengMiTop = Maps.newHashMap();
        }
        Runnable run = () -> {
            ++runSeconds;
//            Bukkit.getScheduler().runTask(plugin, () -> {
//                Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), "tellraw @a {\"text\":\"" + runSeconds + "\",\"bold\":true,\"color\":\"#B6B6DF\"}");
//            });
            // 新的一题
            if (endQuestionTime != null && runSeconds - endQuestionTime >= duration) {
                Bukkit.getScheduler().runTask(plugin, () -> {
                    ConsoleCommandSender sender = Bukkit.getConsoleSender();
                    Bukkit.getServer().dispatchCommand(sender, "title @a times 20 20 20");
                    Bukkit.getServer().dispatchCommand(sender, "title @a subtitle {\"text\":\"GO！！！！！！\",\"color\":\"yellow\"}");
                    Bukkit.getServer().dispatchCommand(sender, String.format("title @a title {\"text\":\"开始！！猜谜！！%d秒！！\",\"color\":\"yellow\"}", timeInterval));
                });
                newOrNextQuestion();
            }
            // 冷却时间
            else if (endQuestionTime != null && runSeconds - endQuestionTime <= duration) {
                int tickDifference = duration - (runSeconds - endQuestionTime);
                switch (tickDifference) {
                    case 5:
                        Bukkit.getScheduler().runTask(plugin, () -> {
                            Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), dengmiComingSoon);
                        });
                        break;
                    case 3:
                    case 2:
                    case 1:
                        Bukkit.getScheduler().runTask(plugin, () -> {
                            Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), String.format(dengmiComingSoonD, tickDifference));
                            Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), "playsound minecraft:entity.camel.dash_ready player @a");
                        });
                        break;
                    default:
                }
            }
            // 答题时间
            else if (startQuestionTime != null && endQuestionTime == null) {
                int tickRemaining = timeInterval + startQuestionTime - runSeconds;
                if (tickRemaining == 0) {
                    endQuestionTime = runSeconds;
                    Bukkit.getScheduler().runTask(plugin, () -> {
                        Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), String.format(answerOutput, nowQuestion.getAnswer()));
                        if (nowQuestion.getMessage() != null) {
                            Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), String.format(messageOutput, nowQuestion.getMessage()));
                        }
                        Bukkit.getScheduler().runTask(plugin, () -> {
                            ConsoleCommandSender sender = Bukkit.getConsoleSender();
                            Bukkit.getServer().dispatchCommand(sender, "title @a times 20 20 20");
                            Bukkit.getServer().dispatchCommand(sender, "title @a title {\"text\":\"回合结束！！\",\"color\":\"yellow\"}");
                        });
                        questionHideAll();
                        writeTopAndSaveLocal();
                        nowQuestion = null;
                    });
                    if (QUESTION_POOL.isEmpty()) {
                        Bukkit.getScheduler().runTask(plugin, () -> {
                            Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), acknowledgments);
                            Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), "poidengmi over");
                        });
                    }
                } else  {
                    switch (tickRemaining) {
                        case 10:
                            Bukkit.getScheduler().runTask(plugin, () -> {
                                Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), dengmiEndWaring);
                            });
                            break;
                        case 3:
                        case 2:
                        case 1:
                            Bukkit.getScheduler().runTask(plugin, () -> {
                                Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), String.format(dengmiComingSoonD, tickRemaining));
                                Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), "playsound minecraft:entity.camel.dash_ready player @a");
                            });
                            break;
                        default:
                    }
                }
            }
        };
        return Bukkit.getScheduler().runTaskTimerAsynchronously(plugin, run, 0, 20);
    }

    private static void writeTopAndSaveLocal() {
        // 写入积分榜
        nowQuestionRightPlayer.forEach((name, score) -> {
            if (dengMiTop.containsKey(name)) {
                dengMiTop.put(name, dengMiTop.get(name) + score);
            } else {
                dengMiTop.put(name, score);
            }
        });
        // 持久化 - 积分榜，剩余题目，运行时间，每题间隔，每题持续时间
        Persistence obj = new Persistence();
        obj.setDengMiTop(dengMiTop);
        obj.setQuestionPool(QUESTION_POOL);
        obj.setDuration(duration);
        obj.setTimeInterval(timeInterval);
        try (ObjectOutputStream oos = new ObjectOutputStream(Files.newOutputStream(new File(plugin.getDataFolder(), "dengMi.bin").toPath()))) {
            // response设置下载文件，文件名称
            oos.writeObject(obj);
//            LOG.info("scoreboard已成功序列化并保存到文件 scoreboard.bin");
        } catch (IOException e) {
//            LOG.error("序列化失败{0}", e.getCause());
        }
    }

    public static void recoverData(MclllCustom mclllCustom, CommandSender sender) {
        plugin = mclllCustom;
        File file1 = new File(plugin.getDataFolder(), "dengMi.bin");
        if (!file1.exists()) {
            return;
        }
        try (ObjectInputStream ois = new ObjectInputStream(Files.newInputStream(file1.toPath()))) {
            Persistence saveData = (Persistence) ois.readObject();
            dengMiTop = saveData.getDengMiTop();
            QUESTION_POOL = saveData.getQuestionPool();
            duration = saveData.getDuration();
            timeInterval = saveData.getTimeInterval();
            if (sender != null) {
                sender.sendMessage(String.format("剩余%d道题目, 题目持续时间：%d秒, 题目间隔：%d秒, 选择题冷却时间：%d秒", QUESTION_POOL.size(), timeInterval, duration, selectCoolDown));
            }
            //            LOG.info("scoreboard已成功反序列化并加载");
        } catch (IOException | ClassNotFoundException e) {
//            LOG.error("反序列化失败", e.getCause());
        }
    }

    public static void stop() {
        nowQuestion = null;
        questionHideAll();
        writeTopAndSaveLocal();
    }

    @Data
    @NoArgsConstructor
    private static class Persistence implements Serializable {
        private Map<String, Integer> dengMiTop;
        private List<Question> questionPool;
        private Integer duration;
        private Integer timeInterval;
    }

    private static void newOrNextQuestion() {
        int index = (int) Math.floor(Math.random() * QUESTION_POOL.size());
        nowQuestion = QUESTION_POOL.get(index);
        QUESTION_POOL.remove(index);
        nowQuestionRightPlayer = Maps.newHashMap();
        // 利用bossBar显示题目
        // 因为方法异步运行Bukkit.getServer()不能在异步方法生效，所以套了一层
        Bukkit.getScheduler().runTask(plugin, () -> {
            AtomicInteger num = new AtomicInteger(0);
            String question = nowQuestion.getQuestion();
            String title = nowQuestion.getType() == QuestionType.INPUT ? question : question.substring(0, question.indexOf("\n"));
            Optional.of(Bukkit.getServer())
                    .map(item -> item.getBossBar(new NamespacedKey("mclll", "xw" + num.getAndIncrement())))
                    .ifPresent(item -> {
                        item.setTitle(title.substring(0, Math.min(title.length(), 45)).replace("\n", "  "));
                        item.setVisible(true);
                    });
            if (title.length() > 45) {
                Optional.of(Bukkit.getServer())
                        .map(item -> item.getBossBar(new NamespacedKey("mclll", "xw" + num.getAndIncrement())))
                        .ifPresent(item -> {
                            item.setTitle(title.substring(45).replace("\n", "  "));
                            item.setVisible(true);
                        });
            }
            if (nowQuestion.getType() != QuestionType.INPUT) {
                Optional.of(Bukkit.getServer())
                        .map(item -> item.getBossBar(new NamespacedKey("mclll", "xw" + num.getAndIncrement())))
                        .ifPresent(item -> {
                            item.setTitle(question.substring(question.indexOf("\n") + 1).replace("\n", "  "));
                            item.setVisible(true);
                        });
            }
            Bukkit.dispatchCommand(Bukkit.getConsoleSender(), newDengMi);
            startQuestionTime = runSeconds;
            endQuestionTime = null;
        });
    }

    public static void checkAnswer(Player player,AsyncPlayerChatEvent event) {
        String message = event.getMessage();
        // 普通题
        boolean check = false;
        if (nowQuestion.getType() == QuestionType.INPUT) {
            check = message.equals(nowQuestion.getAnswer());
            resultAnswer(player, event, check);
        }
        if (nowQuestion.getType() == QuestionType.SELECT) {
            char answer = message.charAt(0);
            boolean possibilityAnswer = message.length() == 1 && ((answer >= 'a' && answer <= 'z') || (answer >= 'A' && answer <= 'Z'));
            if (possibilityAnswer) {
                // 选择题冷却
                if (!nowQuestionRightPlayer.containsKey(player.getName()) && playerSelectCoolDown.containsKey(player.getName()) && playerSelectCoolDown.get(player.getName()) > runSeconds) {
                    player.sendMessage(Component.text("【").color(TextColor.color(182, 182, 223)).decorate(TextDecoration.BOLD)
                            .append(Component.text("新春灯谜").color(NamedTextColor.RED).decorate(TextDecoration.BOLD))
                            .append(Component.text("】").color(TextColor.color(182, 182, 223)).decorate(TextDecoration.BOLD))
                            .append(Component.text(String.format("回答冷却中：%d秒 ~", playerSelectCoolDown.get(player.getName()) - runSeconds)).color(NamedTextColor.RED).decorate(TextDecoration.BOLD)));
                    event.setCancelled(true);
                    return;
                }
                check = message.toUpperCase(Locale.ROOT).equals(nowQuestion.getAnswer());
                resultAnswer(player, event, check);
                playerSelectCoolDown.put(player.getName(), runSeconds + selectCoolDown);
            }
        } else  {
            boolean possibilityAnswer = message.length() == nowQuestion.getAnswer().length() &&
                    message.chars().allMatch(answer -> (answer >= 'a' && answer <= 'z') || (answer >= 'A' && answer <= 'Z'));
            if (possibilityAnswer) {
                // 选择题冷却
                if (playerSelectCoolDown.containsKey(player.getName()) && playerSelectCoolDown.get(player.getName()) > runSeconds) {
                    player.sendMessage(Component.text("【").color(TextColor.color(182, 182, 223)).decorate(TextDecoration.BOLD)
                            .append(Component.text("新春灯谜").color(NamedTextColor.RED).decorate(TextDecoration.BOLD))
                            .append(Component.text("】").color(TextColor.color(182, 182, 223)).decorate(TextDecoration.BOLD))
                            .append(Component.text(String.format("回答冷却中：%d秒 ~", playerSelectCoolDown.get(player.getName()) - runSeconds)).color(NamedTextColor.RED).decorate(TextDecoration.BOLD)));
                    event.setCancelled(true);
                    return;
                }
                char[] charArray = message.toUpperCase(Locale.ROOT).toCharArray();
                Arrays.sort(charArray);
                check = new String(charArray).equals(nowQuestion.getAnswer());
                resultAnswer(player, event, check);
                playerSelectCoolDown.put(player.getName(), runSeconds + selectCoolDown);
            }
        }
    }

    private static void resultAnswer(Player player, AsyncPlayerChatEvent event, boolean check) {
        if (check) {
            if (nowQuestionRightPlayer.containsKey(player.getName())) {
                event.setMessage(playPlay());
            } else {
                // 奖励
                reward(player.getName());
                player.sendMessage(Component.text("【").color(TextColor.color(182, 182, 223)).decorate(TextDecoration.BOLD)
                        .append(Component.text("新春灯谜").color(NamedTextColor.RED).decorate(TextDecoration.BOLD))
                        .append(Component.text("】").color(TextColor.color(182, 182, 223)).decorate(TextDecoration.BOLD))
                        .append(Component.text("恭喜你回答正确 ~").color(NamedTextColor.GREEN).decorate(TextDecoration.BOLD)));
                event.setCancelled(true);
            }
        }
    }

    private static void reward(String player) {
        // 发红包
        Bukkit.getScheduler().runTask(plugin, () -> {
            Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), String.format(giveHongBaoCommand, player));
        });
        // 按名次给奖励
        switch (nowQuestionRightPlayer.size()) {
            // 第一名奖励
            case 0:
                nowQuestionRightPlayer.put(player, 5);
                break;
            // 第二名奖励
            case 1:
                nowQuestionRightPlayer.put(player, 3);
                break;
            case 2:
            // 第三名奖励
                nowQuestionRightPlayer.put(player, 2);
                break;
            default:
            // 其余人奖励
                nowQuestionRightPlayer.put(player, 1);
        }
    }

    private static String playPlay() {
        String[] list = new String[]{
                "荒川er们大家好，我是练习时长两年半的个人练习生",
                "你干嘛啊 ~ 哈哈哈 ~ ~ 哎呦 ~ ~ ",
                "原神！启 ↑ 动 ↓ ",
                "全体目光！看我看我！我宣布个事！新年快乐！！",
                "我是一条Lonely龍"
        };
        return list[new Double(Math.floor(Math.random() * list.length)).intValue()];
    }

    public static void questionAddAll() {
        for (int i = 0; i < 3; i++) {
            Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(),
                    "bossbar set mclll:xw" + i + " players @a"
            );
        }
    }

    public static void questionHideAll() {
        for (int i = 0; i < 3; i++) {
            int finalI = i;
            Optional.of(Bukkit.getServer())
                    .map(item -> item.getBossBar(new NamespacedKey("mclll", "xw" + finalI)))
                    .ifPresent(bar -> {
                        if (bar.isVisible()) {
                            bar.setVisible(false);
                        }
                    });
        }
    }

    public static void overGame() {
        nowQuestion = null;
        startQuestionTime = null;
        endQuestionTime = null;
        nowQuestionRightPlayer = null;
        questionHideAll();
        File file = new File(plugin.getDataFolder(), "dengMi.bin");
        if (file.exists()) {
            file.delete();
        }
    }

    public static boolean isGaming() {
        return nowQuestion != null;
    }
}
